<?php

namespace addons\shopro\library\activity\traits;

use think\Db;
use addons\shopro\traits\CouponSend;
use app\admin\model\shopro\activity\GiftLog;
use addons\shopro\service\Wallet as WalletService;

/**
 * 赠送赠品 （full_gift, groupon_lucky 幸运拼团未拼中）
 */
trait GiveGift
{
    use CouponSend;

    /**
     * 按照规则添加赠送日志
     * @param array|object $order
     * @param array|object $user
     * @param array $info   {"full":"100","types":"coupon=优惠券|score=积分|money=余额|goods=商品","coupon_ids":"赠优惠券时存在","total":"赠送优惠券总金额","score":"积分","money":"余额","goods_ids":"商品时存在",gift_num:"礼品份数"}
     * @return void
     */
    public function addGiftsLog($order, $user, $info)
    {
        \think\Log::write('addGiftsLog - 开始添加礼品记录，订单ID: ' . $order->id);
        
        $rules = $info['discount_rule'];
        \think\Log::write('addGiftsLog - 规则配置: ' . json_encode($rules));

        Db::transaction(function () use ($order, $user, $info, $rules) {
            $types = $rules['types'];
            \think\Log::write('addGiftsLog - 礼品类型: ' . json_encode($types));

            foreach ($types as $type) {
                \think\Log::write('addGiftsLog - 处理类型: ' . $type);
                extract($this->getTypeGift($rules, $type));

                \think\Log::write('addGiftsLog - 类型: ' . $type . ', gift: ' . $gift . ', value: ' . $value);

                $giftLog = new GiftLog();
                $giftLog->activity_id = $info['activity_id'];
                $giftLog->order_id = $order->id;
                $giftLog->user_id = $user->id;
                $giftLog->type = $type;
                $giftLog->gift = $gift;
                $giftLog->value = $value;
                $giftLog->rules = $rules;
                $giftLog->status = 'waiting';
                $giftLog->save();
                
                \think\Log::write('addGiftsLog - 礼品记录已保存，ID: ' . $giftLog->id);
            }
        });
    }


    /**
     * 标记礼品为赠送失败
     */
    public function checkAndFailGift($order, $fail_msg, $errors = null)
    {
        // 找到所有没有赠送的礼品，设置为 fail,fail_msg 订单退款
        $giftLogs = GiftLog::waiting()->where('order_id', $order->id)->lock(true)->select();
        foreach ($giftLogs as $giftLog) {
            $giftLog->status = 'fail';
            $giftLog->fail_msg = $fail_msg;
            $giftLog->errors = $errors;
            $giftLog->save();
        }
    }



    /**
     * 检查并赠送礼品
     *
     * @param array|object $order
     * @param array|object $user
     * @param array $promoInfos
     * @param string $event
     * @return void
     */
    public function checkAndGift($order, $user, $promoInfos, $event)
    {
        foreach ($promoInfos as $info) {
            if ($info['activity_type'] == 'full_gift') {
                $this->checkPromoAndGift($order, $user, $info, $event);
            }
        }
    }


    /**
     * 检查并赠送礼品
     *
     * @param array|object $order
     * @param array|object $user
     * @param array $infos
     * @param string $event
     * @return void
     */
    public function checkPromoAndGift($order, $user, $info, $event)
    {
        if ($info['event'] == $event) {
            // 判断领取次数
            $rules = $info['discount_rule'];
            $gift_num = $rules['gift_num'];     // 礼品数量

            // 查询已发放数量
            $send_num = GiftLog::where('activity_id', $info['activity_id'])->opered()->group('order_id')->count();

            $giftLogs = GiftLog::waiting()
                ->where('activity_id', $info['activity_id'])
                ->where('order_id', $order->id)
                ->select();

            if ($send_num >= $gift_num) {
                // 礼品已经发放完毕
                foreach ($giftLogs as $log) {
                    $log->status = 'fail';
                    $log->fail_msg = '礼品已经发完了';
                    $log->save();
                }

                return false;
            }

            // 查询当前用户已领取数量 (只算赠送成功的)
            $user_send_num = GiftLog::where('user_id', $order->user_id)->where('activity_id', $info['activity_id'])->finish()->group('order_id')->count();
            if ($info['limit_num'] > 0 && $user_send_num >= $info['limit_num']) {
                // 已经领取过了
                foreach ($giftLogs as $log) {
                    $log->status = 'fail';
                    $log->fail_msg = '已经领取过了，每人最多领取 ' . $info['limit_num'] . ' 份';
                    $log->save();
                }

                return false;
            }

            // 赠送礼品
            foreach ($giftLogs as $giftLog) {
                $this->{'gift' . $giftLog->type}($user, $giftLog);
            }
        }
    }



    /**
     * 赠送优惠券
     *
     * @param array|object $user
     * @param array|object $giftLog
     * @return void
     */
    public function giftCoupon($user, $giftLog)
    {
        $couponIds = explode(',', $giftLog->gift);

        $result = $this->giveCoupons($user, $couponIds);

        $giftLog->status = 'finish';
        if ($result['errors']) {
            $giftLog->status = 'fail';
            $giftLog->fail_msg = $result['success'] ? '优惠券部分发放成功' : '优惠券发放失败';
            $giftLog->errors = $result['errors'];
        }

        $giftLog->save();
    }



    /**
     * 赠送积分
     *
     * @param array|object $user
     * @param array|object $giftLog
     * @return void
     */
    public function giftScore($user, $giftLog)
    {
        $score = $giftLog->gift;

        // 增加用户积分
        WalletService::change($user, 'score', $score, 'activity_gift', [
            'activity_id' => $giftLog->activity_id,
            'order_id' => $giftLog->order_id,
            'user_id' => $giftLog->user_id,
            'type' => $giftLog->type,
            'gift' => $giftLog->gift,
            'value' => $giftLog->value,
        ]);

        // 如有上级，按 10% 奖励积分给上级（向下取整，至少 1 分），事件标记为 activity_gift_parent
        try {
            if (isset($user->parent_user_id) && $user->parent_user_id) {
                $parent = \app\admin\model\shopro\user\User::get($user->parent_user_id);
                if ($parent) {
                    $parentBonus = floor($score * 0.10 * 1000000) / 1000000;
                    if ($parentBonus > 0) {
                        WalletService::change($parent, 'score', $parentBonus, 'activity_gift_parent', [
                            'activity_id' => $giftLog->activity_id,
                            'order_id' => $giftLog->order_id,
                            'from_user_id' => $user->id,
                            'from_gift_log_id' => $giftLog->id,
                            'ratio' => '10%',
                        ]);

                        // 如果上级还有上级，按 5% 奖励积分给上级的上级
                        if (isset($parent->parent_user_id) && $parent->parent_user_id) {
                            $grandParent = \app\admin\model\shopro\user\User::get($parent->parent_user_id);
                            if ($grandParent) {
                                $grandParentBonus = floor($score * 0.05 * 1000000) / 1000000;
                                if ($grandParentBonus > 0) {
                                    WalletService::change($grandParent, 'score', $grandParentBonus, 'activity_gift_parent', [
                                        'activity_id' => $giftLog->activity_id,
                                        'order_id' => $giftLog->order_id,
                                        'from_user_id' => $user->id,
                                        'from_gift_log_id' => $giftLog->id,
                                        'ratio' => '5%',
                                    ]);
                                }
                            }
                        }
                    }
                }
            }
        } catch (\Exception $e) {
            \think\Log::write('giftScore parent bonus error: ' . $e->getMessage());
        }

        $giftLog->status = 'finish';
        $giftLog->save();
    }


    /**
     * 赠送余额
     *
     * @param array|object $user
     * @param array|object $giftLog
     * @return void
     */
    public function giftMoney($user, $giftLog)
    {
        $money = $giftLog->gift;

        // 增加用户余额
        WalletService::change($user, 'money', $money, 'activity_gift', [
            'activity_id' => $giftLog->activity_id,
            'order_id' => $giftLog->order_id,
            'user_id' => $giftLog->user_id,
            'type' => $giftLog->type,
            'gift' => $giftLog->gift,
            'value' => $giftLog->value,
        ]);

        $giftLog->status = 'finish';
        $giftLog->save();
    }


    /**
     * 赠送商品（暂不开发）
     *
     * @param array|object $user
     * @param array|object $giftLog
     * @return void
     */
    public function giftGoods($user, $giftLog)
    {
        $goodsIds = explode(',', $giftLog->gift);

        // 赠送商品，暂不开发
        $giftLog->status = 'finish';
        $giftLog->save();
    }




    /**
     * 获取赠送的 gift 和价值
     *
     * @param array $rules
     * @param string $type
     * @return array
     */
    private function getTypeGift($rules, $type)
    {
        $gift = null;
        switch ($type) {
            case 'coupon':
                $gift = $rules['coupon_ids'];
                $value = $rules['total'];
                break;
            case 'score':
                // $gift = 77;
                // $value = 77;
                // 根据数据库分配的code计算积分
                \think\Log::write('getTypeGift - 开始处理score类型积分计算');
                $gift = $this->calculateScoreByCodes($rules);
                $value = $gift; // 积分价值等于积分数量
                \think\Log::write('getTypeGift - score类型积分计算结果: gift=' . $gift . ', value=' . $value);
                break;
            case 'money':
                $gift = $rules['money'];
                $value = $rules['money'];
                break;
            case 'goods':
                $gift = $rules['goods_ids'];
                $value = $rules['goods_ids'];
                break;
        }

        return compact('gift', 'value');
    }

    /**
     * 根据数据库分配的codes计算积分
     * 
     * @param array $rules 规则配置
     * @return int
     */
    private function calculateScoreByCodes($rules)
    {
        \think\Log::write('calculateScoreByCodes - 开始计算积分');
        
        // 获取当前订单的codes
        $orderId = $this->getCurrentOrderId();
        if (!$orderId) {
            \think\Log::write('calculateScoreByCodes - 无法获取订单ID，尝试从全局变量获取');
            $orderId = $GLOBALS['current_order_id'] ?? null;
            if (!$orderId) {
                \think\Log::write('calculateScoreByCodes - 全局变量中也没有订单ID');
                return 0;
            }
        }

        \think\Log::write('calculateScoreByCodes - 获取到订单ID: ' . $orderId);

        // 从数据库获取订单的codes
        $codes = \app\admin\model\shopro\Code::getCodesByOrderId($orderId);
        \think\Log::write('calculateScoreByCodes - 查询到的codes: ' . json_encode($codes));
        
        if (empty($codes)) {
            \think\Log::write('calculateScoreByCodes - 订单ID: ' . $orderId . ' 没有找到codes');
            return 0;
        }

        // 根据codes计算积分
        $totalScore = 0;
        foreach ($codes as $code) {
            // 提取code中的数字部分
            $number = intval(substr($code, 3)); // 去掉RWA前缀
            $score = $this->calculateScoreByCodeNumber($number);
            $totalScore += $score;
            
            \think\Log::write('calculateScoreByCodes - Code: ' . $code . ', 数字: ' . $number . ', 积分: ' . $score);
        }

        \think\Log::write('calculateScoreByCodes - 订单ID: ' . $orderId . ', 总积分: ' . $totalScore);
        return $totalScore;
    }

    /**
     * 根据code数字计算积分
     * 按照RWA积分规则计算：两个阶段的线性递减
     * 
     * @param int $number code中的数字部分（全局购买顺序）
     * @return int
     */
    private function calculateScoreByCodeNumber($number)
    {
        // 确保n值在有效范围内
        if ($number < 1) {
            throw new \Exception('code数字不能小于1');
        } elseif ($number > 1000000) {
            throw new \Exception('code数字不能大于1000000');
        }

        $score = 0;

        if ($number <= 600000) {
            $score = 400 * (1 - 0.8 * ($number - 1) / 599999);
        } else {
            $score = 400 * (0.2 - 0.1 * ($number - 600000) / 400000);
        }

        // 保留6位小数
        $score = round($score, 6);

        // 记录计算过程（用于调试）
        \think\Log::write("积分计算 - Code数字: {$number}, 计算得分: {$score}");

        return $score;
    }

    /**
     * 获取当前订单ID
     * 
     * @return int|null
     */
    private function getCurrentOrderId()
    {
        \think\Log::write('getCurrentOrderId - 开始获取订单ID');

        // 从全局变量中获取（如果存在）
        if (isset($GLOBALS['current_order_id'])) {
            \think\Log::write('getCurrentOrderId - 从全局变量获取: ' . $GLOBALS['current_order_id']);
            return $GLOBALS['current_order_id'];
        }

        // 从调用栈中获取订单ID
        $backtrace = debug_backtrace();
        \think\Log::write('getCurrentOrderId - 调用栈深度: ' . count($backtrace));
        
        foreach ($backtrace as $index => $trace) {
            \think\Log::write("getCurrentOrderId - 调用栈[{$index}]: " . ($trace['class'] ?? '') . '::' . ($trace['function'] ?? ''));
            
            if (isset($trace['args'][0]) && is_object($trace['args'][0])) {
                $arg = $trace['args'][0];
                \think\Log::write('getCurrentOrderId - 参数对象类型: ' . get_class($arg));
                
                if (isset($arg->id) && isset($arg->order_sn)) {
                    \think\Log::write('getCurrentOrderId - 从调用栈获取订单ID: ' . $arg->id);
                    return $arg->id;
                }
            }
        }

        \think\Log::write('getCurrentOrderId - 无法获取订单ID');
        return null;
    }

    /**
     * 测试积分计算函数（用于验证计算是否正确）
     * 
     * @return array
     */
    public function testScoreCalculation()
    {
        $testCases = [
            1,           // 第1个购买用户
            100000,      // 第100,000个购买用户
            600000,      // 第600,000个购买用户
            800000,      // 第800,000个购买用户
            1000000,     // 第1,000,000个购买用户
        ];

        $results = [];
        foreach ($testCases as $number) {
            $score = $this->calculateScoreByCodeNumber($number);
            $results[] = [
                'number' => $number,
                'score' => $score,
                'expected' => $this->getExpectedScore($number)
            ];
        }

        return $results;
    }

    /**
     * 获取期望的积分值（用于测试验证）
     * 
     * @param int $number
     * @return int
     */
    private function getExpectedScore($number)
    {
        if ($number == 1) return 400;
        if ($number == 100000) return 347;
        if ($number == 600000) return 80;
        if ($number == 800000) return 60;
        if ($number == 1000000) return 40;
        return 0;
    }
}
